﻿/**
 * @file NandHal.h
 * @brief NAND硬件抽象层，负责通道、设备、块的管理和命令队列处理。
 */
#ifndef __NandHal_h__
#define __NandHal_h__

#include <vector>
#include <queue>
#include <memory>
#include "boost/lockfree/spsc_queue.hpp"
#include "SimFrameworkBase/FrameworkThread.h"
#include "Nand/Sim/NandChannel.h"
#include "Buffer/Hal/BufferHal.h"

/**
 * @class NandHal
 * @brief NAND硬件抽象层，负责仿真NAND设备的管理和命令处理。
 */
class NandHal : public FrameworkThread
{
public:
    /**
     * @struct Geometry
     * @brief NAND设备几何参数。
     */
    struct Geometry
    {
        U8 ChannelCount;      /**< 通道数 */
        U8 DevicesPerChannel; /**< 每通道设备数 */
        U32 BlocksPerDevice;  /**< 每设备块数 */
        U32 PagesPerBlock;    /**< 每块页数 */
        U32 BytesPerPage;     /**< 每页字节数 */
    };

public:
    /**
     * @brief 构造函数。
     */
    NandHal();

    /**
     * @brief 初始化设备几何参数和缓冲区管理器。
     * @note 当前设计仅支持同构NAND设备配置（即所有NAND设备参数一致）。PreInit仅用于仿真系统（实际硬件无此接口）。
     * @param geometry 设备几何参数
     * @param bufferHal 缓冲区管理器
     */
    void PreInit(const Geometry &geometry, std::shared_ptr<BufferHal> bufferHal);

public:
    /**
     * @brief 初始化NAND仿真系统。
     */
    void Init();
    /**
     * @brief 设置扇区信息。
     * @param sectorInfo 扇区信息结构体
     */
    void SetSectorInfo(const SectorInfo &sectorInfo);

public:
    /**
     * @brief 获取设备几何参数。
     * @return 当前设备几何参数
     */
    inline Geometry GetGeometry() const { return _Geometry; }

public:
    /**
     * @struct NandAddress
     * @brief NAND地址结构体。
     */
    struct NandAddress
    {
        tChannel Channel;         /**< 通道号 */
        tDeviceInChannel Device;  /**< 通道内设备号 */
        tBlockInDevice Block;     /**< 设备内块号 */
        tPageInBlock Page;        /**< 块内页号 */
        tSectorInPage Sector;     /**< 页内扇区号 */
        tSectorCount SectorCount; /**< 扇区数量 */
    };

    struct CommandDesc;
    /**
     * @class CommandListener
     * @brief 命令完成回调接口。
     */
    class CommandListener
    {
    public:
        /**
         * @brief 命令完成回调。
         * @param command 命令描述
         */
        virtual void HandleCommandCompleted(const CommandDesc &command) = 0;
    };

    /**
     * @struct CommandDesc
     * @brief NAND操作命令描述。
     */
    struct CommandDesc
    {
        /**
         * @enum Op
         * @brief 操作类型枚举。
         */
        enum class Op
        {
            Read,         /**< 读操作 */
            Write,        /**< 写操作 */
            Erase,        /**< 擦除操作 */
            ReadPartial,  /**< 部分读操作 */
            WritePartial, /**< 部分写操作 */
        };

        /**
         * @enum Status
         * @brief 命令状态枚举。
         */
        enum class Status
        {
            Success,    /**< 成功 */
            Uecc,       /**< 纠错失败 */
            WriteError, /**< 写入错误 */
            EraseError, /**< 擦除错误 */
        };

        NandAddress Address;           /**< NAND地址 */
        Op Operation;                  /**< 操作类型 */
        Status CommandStatus;          /**< 命令状态 */
        Buffer Buffer;                 /**< 关联缓冲区 */
        tSectorOffset BufferOffset;    /**< 缓冲区偏移 */
        tSectorOffset DescSectorIndex; /**< 命令描述扇区索引 */
        CommandListener *Listener;     /**< 命令完成回调 */
    };

    /**
     * @brief 将命令加入队列。
     * @param command 命令描述
     */
    void QueueCommand(const CommandDesc &command);
    /**
     * @brief 检查命令队列是否为空。
     * @return 是否为空
     */
    bool IsCommandQueueEmpty() const;

public:
    /**
     * @brief 读整页数据。
     */
    bool ReadPage(tChannel channel, tDeviceInChannel device, tBlockInDevice block, tPageInBlock page, const Buffer &outBuffer);
    /**
     * @brief 读部分页数据。
     */
    bool ReadPage(
        const tChannel &channel,
        const tDeviceInChannel &device,
        const tBlockInDevice &block,
        const tPageInBlock &page,
        const tSectorInPage &sector,
        const tSectorCount &sectorCount,
        const Buffer &outBuffer,
        const tSectorOffset &bufferOffset);

    /**
     * @brief 写整页数据。
     */
    void WritePage(tChannel channel, tDeviceInChannel device, tBlockInDevice block, tPageInBlock page, const Buffer &inBuffer);
    /**
     * @brief 写部分页数据。
     */
    void WritePage(
        const tChannel &channel,
        const tDeviceInChannel &device,
        const tBlockInDevice &block,
        const tPageInBlock &page,
        const tSectorInPage &sector,
        const tSectorCount &sectorCount,
        const Buffer &inBuffer,
        const tSectorOffset &bufferOffset);

    /**
     * @brief 擦除指定块。
     */
    void EraseBlock(tChannel channel, tDeviceInChannel chip, tBlockInDevice block);

protected:
    /**
     * @brief 线程主循环，处理NAND操作。
     */
    virtual void Run() override;

private:
    /**
     * @brief 处理NAND操作命令队列。
     */
    void ProcessNandOperation();

private:
    std::shared_ptr<BufferHal> _BufferHal;                                   ///< 缓冲区管理器
    std::vector<NandChannel> _NandChannels;                                  ///< 通道集合
    std::unique_ptr<boost::lockfree::spsc_queue<CommandDesc>> _CommandQueue; ///< 命令队列
    Geometry _Geometry;                                                      ///< 设备几何参数
    SectorInfo _SectorInfo;                                                  ///< 扇区信息
};

#endif
